#ifndef __WIZ_BASE_TYPE_STRING_HPP__SHANHAOBO_19800429__
#define __WIZ_BASE_TYPE_STRING_HPP__SHANHAOBO_19800429__

#include <stdarg.h>
#include <string>
#include <sstream>
#include <ctype.h>

#include "./WizBaseTypeBase.hpp"
#include "./WizBaseTypeSize.hpp"
#include "./WizBaseTypeCount.hpp"

namespace Wiz
{
    namespace Base
    {
        namespace TString
        {
            template<class BaseType>
            class Type : public BaseType
            {
            public:
                typedef BaseType                            tSuper;
                WIZ_DECLARE_CLASS_THIS(Type);

                typedef typename tSuper::value_type         tChar;
                typedef tSuper                              tValue;
                typedef typename tSuper::size_type          tSize;
                typedef typename tSuper::iterator           tIterator;
                typedef typename tSuper::const_iterator     tIteratorConst;

                typedef typename tSuper::traits_type        tTraits;

                typedef tChar const * const                 tFixedConstCharPtr;
                typedef tChar const * const                 tFixedConstStr;
                typedef tChar const *                       tConstCharPtr;
                typedef tChar const *                       tConstStr;
            public:
                static ::Wiz::USize::Type GetLength(const tChar* InStr)
                {
                    return static_cast<::Wiz::USize::Type>(tTraits::length(InStr));
                }
            public:
                Type() : tSuper()
                {
                }
                Type(const tChar* _Ptr) : tSuper( _Ptr )
                {
                }

                Type(const tSuper& _Right) : tSuper( _Right )
                {
                }

                Type(tThisIn _Right) : tSuper( _Right )
                {
                }

                Type(tThisIn _Right, tSize _Roff, tSize _Count = npos) : tSuper( _Right, _Roff, _Count )
                {
                }

                Type(const tChar* _Ptr, tSize _Count) : tSuper( _Ptr, _Count )
                {
                }

                template<class _It>
                Type(_It first, _It last) : tSuper( first, last )
                {
                }

                const tSuper& GetSuper() const
                {
                    return *this;
                }
            public:
                ::Wiz::Bool::Type operator==(tThisIn _Right)
                {
                    return tSuper::compare(_Right) == 0;
                }

                ::Wiz::Bool::Type operator!=(tThisIn _Right)
                {
                    return tSuper::compare(_Right) != 0;
                }

                ::Wiz::Bool::Type operator==(const tChar *_Ptr)
                {
                    return tSuper::compare(_Ptr) == 0;
                }

                ::Wiz::Bool::Type operator!=(const tChar *_Ptr)
                {
                    return tSuper::compare(_Ptr) != 0;
                }

                tThis& operator=( const tChar *_Ptr )
                {
                    tSuper::operator=( _Ptr );
                    return *this;
                }

                tThis& operator=( tThisIn _Right )
                {
                    tSuper::operator=( _Right );
                    return *this;
                }

                tThis& operator=( const tSuper& _Right )
                {
                    tSuper::operator=( _Right );
                    return *this;
                }

                tThis& operator+=( const tChar* _Ptr )
                {
                    tSuper::operator+=( _Ptr );
                    return *this;
                }

                tThis& operator+=( const tChar _Ch )
                {
                    tSuper::operator+=( _Ch );
                    return *this;
                }

                tThis& operator+=( tThisIn _Right )
                {
                    tSuper::operator+=( _Right );
                    return *this;
                }

                tThis operator+( const tChar* _Ptr )
                {
                    tThis _Tmp = *this;
                    return (_Tmp += _Ptr);
                }

                tThis operator+( tThisIn _Right )
                {
                    tThis _Tmp = *this;
                    return (_Tmp += _Right);
                }

            public:
                WIZ_INLINE tFixedConstCharPtr GetConstBuffer() const
                {
                    return tSuper::c_str();
                }

				WIZ_INLINE tChar* GetBuffer() const
				{
					return const_cast<tChar*>(GetConstBuffer());
				}

                WIZ_INLINE tFixedConstStr GetCStr() const
                {
                    return GetConstBuffer();
                }
            public:
                operator tFixedConstStr()
                {
                    return this->GetCStr();
                }
            public:
                ::Wiz::Void::Type Resize(::Wiz::USize::In NewSize)
                {
                    tSuper::resize(static_cast<tSize>(NewSize));
                }

                ::Wiz::USize::Type Size() const
                {
                    return static_cast<::Wiz::USize::Type>(tSuper::size());
                }

                ::Wiz::USize::Type Capacity() const
                {
                    return static_cast<::Wiz::USize::Type>(tSuper::capacity());
                }

                ::Wiz::Bool::Type IsEmpty() const
                {
                    return tSuper::empty();
                }

				::Wiz::Void::Type Clear()
				{
					tSuper::clear();
				}

                ::Wiz::Bool::Type HasChar(tChar C)
                {
                    if (Size() > 0)
                    {
                        return Find(C) != ::Wiz::USize::Invalid;
                    }

                    return ::Wiz::Bool::False;
                }

                //////////////////////////////////////////////////////////////////////////
                ::Wiz::USize::Type Find(tChar C, ::Wiz::USize::In Off = 0)
                {
                    tSize FindPos = tSuper::find(C, static_cast<tSize>(Off));
                    return FindPos == tSuper::npos ? ::Wiz::USize::Invalid : static_cast<::Wiz::USize::Type>(FindPos);
                }
                ::Wiz::USize::Type Find(const tChar* SubStrPtr, ::Wiz::USize::In Off = 0)
                {
                    tSize FindPos = tSuper::find(SubStrPtr, static_cast<tSize>(Off));
                    return FindPos == tSuper::npos ? ::Wiz::USize::Invalid : static_cast<::Wiz::USize::Type>(FindPos);
                }

                /// [OffBegin, OffEnd)
                ::Wiz::USize::Type Find(tChar C, ::Wiz::USize::In OffBegin, ::Wiz::USize::In OffEnd)
                {
                    WIZ_ASSERT(OffEnd >= OffBegin);
                    WIZ_ASSERT(OffEnd <= Size());

                    tConstStr Curr = GetCStr() + OffBegin;
                    tFixedConstStr EndPtr = GetCStr() + (OffEnd == 0 ? Size() : OffEnd);
                    for (; Curr < EndPtr; Curr++)
                    {
                        if (*Curr == C)
                        {
                            return Curr - GetCStr();
                        }
                    }

                    return ::Wiz::USize::Invalid;
                }
                /// [OffBegin, OffEnd)
                ::Wiz::USize::Type Find(const tChar* SubStrPtr, ::Wiz::USize::In SubLen, ::Wiz::USize::In OffBegin, ::Wiz::USize::In OffEnd)
                {
                    WIZ_ASSERT(OffEnd >= OffBegin);
                    WIZ_ASSERT(OffEnd <= Size());

                    tConstStr Curr = GetCStr() + OffBegin;
                    tFixedConstStr EndPtr = GetCStr() + (OffEnd == 0 ? Size() : OffEnd) - SubLen + 1;
                    for (; Curr < EndPtr; Curr++)
                    {
                        if (::memcmp(Curr, SubStrPtr, SubLen) == 0)
                        {
                            return Curr - GetCStr();
                        }
                    }

                    return ::Wiz::USize::Invalid;
                }
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                /// [OffBegin, OffEnd)
                ::Wiz::Count::Type FindCount(tChar C, ::Wiz::USize::In OffBegin = 0, ::Wiz::USize::In OffEnd = 0)
                {
                    WIZ_ASSERT(OffEnd >= OffBegin);
                    ::Wiz::USize::Type Temp(OffBegin);
                    ::Wiz::Count::Type Cnt = -1;
                    do
                    {
                        Temp = Find(C, Temp, OffEnd);
                        Cnt++;
                    } while (Temp != ::Wiz::USize::Invalid);

                    return Cnt;
                }
                /// [OffBegin, OffEnd)
                ::Wiz::Count::Type FindCount(const tChar* SubStrPtr, ::Wiz::USize::In SubLen, ::Wiz::USize::In OffBegin = 0, ::Wiz::USize::In OffEnd = 0)
                {
                    WIZ_ASSERT(OffEnd >= OffBegin);
                    ::Wiz::USize::Type Temp(OffBegin);
                    ::Wiz::Count::Type Cnt = -1;
                    do
                    {
                        Temp = Find(SubStrPtr, SubLen, Temp + SubLen, OffEnd);
                        Cnt++;
                    } while (Temp != ::Wiz::USize::Invalid);

                    return Cnt;
                }
                //////////////////////////////////////////////////////////////////////////

                ::Wiz::USize::Type FindMatch(tChar C1, tChar C2, ::Wiz::USize::In Off = 0)
                {
                    tSize FindPos = tSuper::find(C1, static_cast<tSize>(Off));
                    if (FindPos == tSuper::npos)
                    {
                        return ::Wiz::USize::Invalid;
                    }

                    tChar Temp[2];
                    Temp[0] = C1;
                    Temp[1] = C2;

                    ::Wiz::Count::Type Cnt = 1;
                    do
                    {
                        FindPos = tSuper::find_first_of(Temp, FindPos + 1, 2);
                        if (FindPos == tSuper::npos)
                        {
                            return ::Wiz::USize::Invalid;
                        }

                        if (GetBuffer()[FindPos] == C1)
                        {
                            Cnt++;
                        }
                        else
                        {
                            WIZ_ASSERT(GetBuffer()[FindPos] == C2);
                            Cnt--;
                        }

                    } while(Cnt != 0);

                    return static_cast<::Wiz::USize::Type>(FindPos);
                }

                ::Wiz::USize::Type FindMatch(const tChar* Sub1StrPtr, const tChar* Sub2StrPtr, ::Wiz::USize::In Off = 0)
                {
                    ::Wiz::USize::Type BeginOff = Find(Sub1StrPtr, Off);
                    if (BeginOff == ::Wiz::USize::Invalid)
                    {
                        return ::Wiz::USize::Invalid;
                    }

                    ::Wiz::USize::TypeConst Sub1Len = tThis::GetLength(Sub1StrPtr);
                    ::Wiz::USize::TypeConst Sub2Len = tThis::GetLength(Sub2StrPtr);
                    ::Wiz::Count::Type Sub1Cnt = 1;

                    ::Wiz::USize::Type TempOff(BeginOff + Sub1Len);
                    ::Wiz::USize::Type EndOff = 0;
                    do 
                    {
                        EndOff = Find(Sub2StrPtr, TempOff);
                        if (EndOff == ::Wiz::USize::Invalid)
                        {
                            return ::Wiz::USize::Invalid;
                        }
                        Sub1Cnt--;
                        Sub1Cnt += FindCount(Sub1StrPtr, Sub1Len, TempOff, EndOff);
                        TempOff = EndOff + Sub2Len; 
                    } while (Sub1Cnt != 0);

                    return EndOff;
                }
            public:
                ::Wiz::Bool::Type ICompare(tThisIn IStr) const
                {
                    if (Size() != IStr.Size())
                    {
                        return ::Wiz::Bool::False;
                    }
                    return ::Wiz::StrCmpIgnoreCase(GetCStr(), IStr.GetCStr());
                }
            };
        } /// end of namespace String
    } /// end of namespace Base
    ///////////////////////////////////////////////////

	///////////////////////////////////////////////////
    namespace String
    {
        WIZ_DECLARE(::Wiz::Base::TString::Type<::std::string>);
        static const ::Wiz::String::Type::tSize NPos = ::Wiz::String::Type::tSuper::npos;

        namespace Char
        {
            typedef ::Wiz::String::Type::value_type Type;
            WIZ_DECLARE(::Wiz::String::Char::Type);
            static ::Wiz::String::Char::TypeConst Terminator = '\0';
        } /// end of namespace Char
    } /// end of namespace String

    namespace WString
    {
        WIZ_DECLARE(::Wiz::Base::TString::Type<::std::wstring>);
        static const ::Wiz::WString::Type::tSize NPos = ::Wiz::WString::Type::tSuper::npos;

        namespace Char
        {
            typedef ::Wiz::WString::Type::value_type Type;
            WIZ_DECLARE(::Wiz::WString::Char::Type);
            static ::Wiz::WString::Char::TypeConst Terminator = L'\0';
        } /// end of namespace Char
    } /// end of namespace WString

    namespace String
    {
        WIZ_INLINE ::Wiz::Void::Type MakeCStr(::Wiz::String::Out OStr, ::Wiz::Char::InPtr CStrPtr, ::Wiz::USize::In SZ)
        {
            ::Wiz::USize::TypeConst NewSz = SZ + (CStrPtr[SZ - 1] == ::Wiz::Char::Terminator) ? 0 : 1;
            OStr.Resize(NewSz);
            memcpy(OStr.GetBuffer(), CStrPtr, NewSz - 1);
            OStr.GetBuffer()[NewSz - 1] = ::Wiz::Char::Terminator;
        }


        WIZ_INLINE ::Wiz::Char::Ptr DuplicateToCStr(::Wiz::String::In InStr)
        {
            ::Wiz::USize::TypeConst NewSz = InStr.Size() + (InStr.GetBuffer()[InStr.Size() - 1] == ::Wiz::Char::Terminator) ? 0 : 1;
            ::Wiz::Char::Ptr ResultPtr = new ::Wiz::Char::Type[NewSz];

            memcpy(ResultPtr, InStr.GetCStr(), NewSz);

            return ResultPtr;
        }
    } /// end of namespace String

    namespace WString
    {
        WIZ_INLINE ::Wiz::Void::Type MakeCStr(::Wiz::WString::Out OStr, ::Wiz::WChar::InPtr CStrPtr, ::Wiz::USize::In SZ)
        {
            ::Wiz::USize::TypeConst NewSz = SZ + (CStrPtr[SZ - 1] == ::Wiz::WChar::Terminator) ? 0 : 1;
            OStr.Resize(NewSz);
            memcpy(OStr.GetBuffer(), CStrPtr, NewSz - 1);
            OStr.GetBuffer()[NewSz - 1] = ::Wiz::WChar::Terminator;
        }
    }  /// end of namespace WString

	///////////////////////////////////////////////////
	WIZ_EXPORT ::Wiz::Bool::Type WCharStrToMultiBytesStr(::Wiz::String::Out MBS, ::Wiz::WString::In WS, ::Wiz::Char::InPtr CP/*CodePage*/);
	WIZ_EXPORT ::Wiz::Bool::Type MultiBytesStrToWCharStr(::Wiz::WString::Out WS, ::Wiz::String::In MBS, ::Wiz::Char::InPtr CP/*CodePage*/);
	///////////////////////////////////////////////////

    ///////////////////////////////////////////////////
    namespace CStr
    {
        template<typename IteratorT>
        WIZ_INLINE IteratorT GetLast(IteratorT Frst)
        {
            while (*Frst) Frst++;
            return Frst;
        }
    } /// end of namespace CStr
    ///////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////////////////

} /// end of namespace Wiz

#endif /*__WIZ_BASE_TYPE_STRING_HPP__SHANHAOBO_19800429__*/
